//
// Created by wxd on 2025/8/22.
//

#pragma once

#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/trigonometric.hpp>
#include "../wrapper/log/Logger.h"
#include "../wrapper/monitor/GLDebug.hpp"
#include "../global/ChineseOutput.hpp"
#include "../application/app/Application.h"
#include "../global/EngineDataProperties.h"
#include "../glFramework/shader/Shader.h"
#include "../glFramework/constant/engine_layout.h"
#include "../glFramework/texture/Texture.h"
#include "../glFramework/utils/ResourceLoadUtils.h"
#include "../glFramework/bo/VBO.h"
#include "../glFramework/bo/VAO.h"
#include "../glFramework/constant/engine_uniform.h"
#include <memory>

#include "bo/EBO.h"
#include "../global/output.hpp"
#include "../application/camera/PerspectiveCamera.h"
#include "../application/camera/control/TrackBallCameraControl.h"
#include "../application/camera/control/GameFPSCameraControl.h"

#include "../application/frame/FrameManager.h"

#include "../glFramework/geo/Cube.h"
#include "../glFramework/geo/Sphere.h"
#include "../glFramework/light/phong/PhongLightMode.h"
#include "../glFramework/light/phong/AmbientLight.h"
#include "../glFramework/light/phong/ParallelLight.h"

#include "../math/matrix/MatrixTransformUtils.hpp"

/**
 * 测试引擎的相机系统
 *
 */
struct MvpMatrix {
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = glm::mat4(1.0f);
    glm::mat4 proj = glm::mat4(1.0f);
};

inline const char* vertexPath = "../demo/shader/phong_light_scene/bling_phong_vertex.glsl";
inline const char* fragmentPath = "../demo/shader/phong_light_scene/bling_phong_fragment.glsl";
inline const char* texPath = "../demo/texture/earth.png";
inline MvpMatrix mvpMatrix;

inline TrackBallCameraControl mController;
inline GameFPSCameraControl mFPSController;
inline PerspectiveCamera mCamera;

inline void onResize(int w, int h) {
    glViewport(0, 0, w, h);
}

inline void onKeyBoard(int key, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
    }

    mFPSController.onKeyBoard(key, action, mods);
}

inline void onCursor(double xpos, double ypos) {
    mFPSController.onCursor(xpos, ypos);
}

inline void onMouse(int button, int action, int mods) {
    double x, y;
    EngineApp.getCurrentCursorPos(&x, &y);
    mFPSController.onMouse(button, action, x, y);
}

inline void render() {
    ChineseOutput::init();
    EngineApp.initWindowConfig(3, 3, GLFW_OPENGL_CORE_PROFILE,
        2560, 1800,  "FPS Camera Coontrol");
    // EngineApp.initDefaultWindowConfig();
    EngineApp.setResizeCallback(onResize);
    EngineApp.setKeyBoardCallback(onKeyBoard);
    EngineApp.setCursorCallback(onCursor);
    EngineApp.setMouseCallback(onMouse);
    EngineApp.setHideMouseCursor(false);
    EngineApp.init();

    auto frameCounter = FrameCounter::Builder().setEmaAlpha(0.95f).setHistoryMaxSize(60).build();
    FrameManager::getInstance().setFrameCounter(std::move(frameCounter)); // 注意：独占指针的拷贝构造是被delete的，所以必须通过std::move的方式传递

    PerspectiveParams param;
    param.fov = 45.f;
    param.aspect = EngineApp.getWindowAspectRatio();
    param.zNear = 0.1f;
    param.zFar = 100.f;
    mCamera.setPerspectiveParams(param);
    mCamera.setCameraParams(glm::vec3(0.f, 0.f, 3.f), glm::vec3(0.f, 1.f, 0.f), glm::vec3(1.f, 0.f, 0.f));
    mFPSController.setMouseCenter(EngineApp.getCurrentWindowWidth(), EngineApp.getCurrentWindowHeight());
    mFPSController.setCamera(&mCamera);
    mFPSController.setSpeed(0.005f);
    mFPSController.setSensitivity(0.03f);
    mFPSController.setPitchRange(89.0f, -89.0f);

    AmbientLight ambient = AmbientLight(
        glm::vec4(0.45f, 0.32f, 0.39f, 1.f),
        glm::vec4(0.91f, 0.88f, 0.95f, 1.f)
    );

    ParallelLight parallel = ParallelLight(
        glm::vec4(0.8f, 0.7f, 0.81f, 1.f),
        glm::vec4(0.77f, 0.71f, 0.71f, 1.f),
        glm::vec3(0.f, 0.f,  -1.f)
    );

    PhongLightMode phongMode;
    phongMode.setAmbientLight(ambient);
    phongMode.setLight(parallel);

    Cube cube = Cube(1.f, glm::vec3(0.f, 0.f, -3.f));

    Texture texture(texPath);
    texture.setSamplerName(EngineUniform::uTexUnit);

    std::unique_ptr<Shader> shader = std::make_unique<Shader>(vertexPath, fragmentPath);


    mvpMatrix.view = glm::lookAt(glm::vec3(0.f, 1.f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    mvpMatrix.proj = glm::perspective(glm::radians(45.f), EngineApp.getWindowAspectRatio(), 0.f, 100.f);

    while (EngineApp.update()) {
        glEnable(GL_DEPTH_TEST);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        mFPSController.update();
        FrameManager::getInstance().updateFrameCounter();

        shader->bindProgram();
        shader->setUniform("uModel", mvpMatrix.model);
        shader->setUniform("uView", mCamera.getViewMatrix());
        shader->setUniform("uProj", mCamera.getProjectMatrix());
        shader->setUniform(texture.getSamplerName(), texture.getTextureUnit()); // 采样0号单元
        shader->setUniform(EngineUniform::uNormalMat, getNormalMatrix(mvpMatrix.model));
        phongMode.setCameraPos(mCamera.m_Position);
        phongMode.uniform(*shader);
        cube.getVAO()->bind();
        cube.draw();
        cube.getVAO()->unbind();
        shader->unbindProgram();
    }

    cube.getVAO()->destroy();
    cube.getEBO()->destroy();
    shader->deleteProgram();
    EngineApp.destroy();
}